/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.bemanager.service.cdmparser;

//using Common.Logging;

import com.inspur.edp.cef.designtime.api.element.GspElementDataType;
import lombok.var;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

public class CdmReader {

  ///#region 字段属性
//    private final ParserUtil Util = new ParserUtil();
  private String pdmFile;
  private java.util.List<CdmTableInfo> tables;
  private java.util.List<CdmColumnInfo> dataItems;
  private final String exceptionCode = "CdmReader";
  private Document xmlDoc;
//    private XmlNamespaceManager xmlnsManager;
//    private Regex regex;

  private CdmReader() {
    // TODO: 在此处添加构造函数逻辑
    //xmlDoc = new XmlDocument();
    //xmlDoc = new XmlDocument();
    //xmlDoc.Load(pdmFile);
    //xmlnsManager = new XmlNamespaceManager(xmlDoc.NameTable);
    //xmlnsManager.AddNamespace("a", "attribute");
    //xmlnsManager.AddNamespace("c", "collection");
    //xmlnsManager.AddNamespace("o", "object");
    //XmlNode xnTables = xmlDoc.SelectSingleNode("//" + cTables, xmlnsManager);
  }

  public CdmReader(String xml) {
    this();
    if (xmlDoc == null) {
      try {
        xmlDoc = DocumentHelper.parseText(xml);
      } catch (DocumentException e) {
        throw new RuntimeException("CDM文件解析失败", e);
      }
//			xmlDoc = new XmlDocument();
//			xmlDoc.InnerXml = xml;
//            xmlnsManager = new XmlNamespaceManager(xmlDoc.NameTable);
//            xmlnsManager.AddNamespace("a", "attribute");
//            xmlnsManager.AddNamespace("c", "collection");
//            xmlnsManager.AddNamespace("o", "object");
    }
    initData();
  }

  ///#endregion

  ///#region 构造函数

  public final String getPdmFile() {
    return pdmFile;
  }

  public final java.util.List<CdmTableInfo> getTables() {
    return tables;
  }

  ///#endregion

  public final java.util.List<CdmColumnInfo> getDataItems() {
    return dataItems;
  }

  ///#region table

  private void initData() {
    // 读取字段集合
    if (dataItems == null) {
      dataItems = new java.util.ArrayList<CdmColumnInfo>();
      Element xnDataItems = ((Element) xmlDoc.getRootElement()
          .selectSingleNode("//" + CdmNames.cDataItems));
      for (Element xnTable : xnDataItems.elements()) {
        dataItems.add(getColumn(xnTable));
      }
//			dataItems = new java.util.ArrayList<CdmColumnInfo>();
//			XmlNode xnDataItems = xmlDoc.SelectSingleNode("//" + CdmNames.cDataItems, xmlnsManager);
//			for (XmlNode xnTable : xnDataItems.ChildNodes)
//			{
//				dataItems.add(GetColumn(xnTable));
//			}
    }

    // 读取表
    if (tables == null) {
      tables = new java.util.ArrayList<CdmTableInfo>();
      Element xnDataItems = ((Element) xmlDoc.getRootElement()
          .selectSingleNode("//" + CdmNames.cEntities));
      for (Element xnTable : xnDataItems.elements()) {
        tables.add(getTable(xnTable));
      }

//            XmlNode xnTables = xmlDoc.SelectSingleNode("//" + CdmNames.cEntities, xmlnsManager);
//            for (XmlNode xnTable : xnTables.ChildNodes) {
//                getTables().add(GetTable(xnTable));
//            }
    }

  }

  ///#endregion

  ///#region columns

  private CdmTableInfo getTable(Element xnTable) {
    CdmTableInfo mTable = new CdmTableInfo();
//        XmlElement xe = (XmlElement) xnTable;
    String tableId = xnTable.attribute("Id").getValue();
//        mTable.setTableId(xe.GetAttribute("Id"));
    mTable.setTableId(tableId);
//        XmlNodeList xnTProperty = xe.ChildNodes;
    for (Element xnP : xnTable.elements()) {
      switch (xnP.getQName().getQualifiedName()) {
        case CdmNames.aObjectID:
          mTable.setObjectID(xnP.getStringValue());
          break;
        case CdmNames.aName:
          mTable.setName(xnP.getStringValue());
          break;
        case CdmNames.aCode:
          mTable.setCode(xnP.getStringValue());
          break;
        case CdmNames.aCreationDate:
          mTable.setCreationDate(Integer.parseInt(xnP.getText()));
          break;
        case CdmNames.aCreator:
          mTable.setCreator(xnP.getStringValue());
          break;
        case CdmNames.aModificationDate:
          mTable.setModificationDate(Integer.parseInt(xnP.getText()));
          break;
        case CdmNames.aModifier:
          mTable.setModifier(xnP.getStringValue());
          break;
        case CdmNames.aComment:
          mTable.setComment(xnP.getStringValue());
          break;
        case CdmNames.aPhysicalOptions:
          mTable.setPhysicalOptions(xnP.getStringValue());
          break;
        case CdmNames.cAttributes:
          initColumns(xnP, mTable);
          break;
        case CdmNames.aIdentifiers:
          initKeys(xnP, mTable);
          break;
        case CdmNames.cPrimaryIdentifier:
          //XmlElement idNode = (XmlElement)Util.GetChildNode(xnP, "o:Identifier");
//                    XmlElement idNode = (XmlElement) xnP.ChildNodes[0];
          Element idNode = xnP.elements().stream().findFirst().get();
          mTable.setPrimaryItemId(getRefItemId(idNode));
          break;
      }
    }
    return mTable;
  }

  private void initColumns(Element xnColumns, CdmTableInfo pTable) {
    for (Element xnColumn : xnColumns.elements()) {
      CdmColumnInfo columnInfo = getColumn(xnColumn);
      updateTableColumnsInfo(columnInfo);
      pTable.addColumn(columnInfo);
    }
  }

  private CdmColumnInfo getColumn(Element xnColumn) {
    CdmColumnInfo mColumn = new CdmColumnInfo();
//		XmlElement xe = (XmlElement)xnColumn;
    String columnId = xnColumn.attribute("Id").getValue();
//		mColumn.setColumnId(xe.GetAttribute("Id"));
    mColumn.setColumnId(columnId);
//		XmlNodeList xnCProperty = xe.ChildNodes;
    for (Element xnP : xnColumn.elements()) {
      switch (xnP.getQName().getQualifiedName()) {
        case CdmNames.aObjectID:
          mColumn.setObjectID(xnP.getStringValue());
          break;
        case CdmNames.aName:
          mColumn.setName(xnP.getStringValue());
          break;
        case CdmNames.aCode:
          mColumn.setCode(xnP.getStringValue());
          break;
        case CdmNames.aCreationDate:
          mColumn.setCreationDate(Integer.parseInt(xnP.getText()));
          break;
        case CdmNames.aCreator:
          mColumn.setCreator(xnP.getStringValue());
          break;
        case CdmNames.aModificationDate:
          mColumn.setModificationDate(Integer.parseInt(xnP.getText()));
          break;
        case CdmNames.aModifier:
          mColumn.setModifier(xnP.getStringValue());
          break;
        case CdmNames.aComment:
          mColumn.setComment(xnP.getStringValue());
          break;
        case CdmNames.aDataType:
          mColumn.setDataType(getDataType(xnP.getText()));
          break;
        case CdmNames.aLength:
          String length = xnP.getText();
          mColumn.setLength(isNullOrEmpty(length) ? "0" : length);
          break;
        case CdmNames.aPrecision:

          String precision = xnP.getText();
          mColumn.setPrecision(isNullOrEmpty(precision) ? "0" : precision);
          break;
        case CdmNames.aIdentity:
          //mColumn.Identity = pgConvert.ConvertToBooleanPG(xnP.InnerText);
          break;
        case CdmNames.aMandatory:
          //mColumn.Mandatory = pgConvert.ConvertToBooleanPG(xnP.InnerText);
          break;
        case CdmNames.aPhysicalOptions:
          mColumn.setPhysicalOptions(xnP.getStringValue());
          break;
        case CdmNames.aExtendedAttributesText:
          mColumn.setExtendedAttributesText(xnP.getStringValue());
          break;
        case CdmNames.cDataItem:
          //XmlElement idNode = (XmlElement)Util.GetChildNode(xnP, oDataItem);
//                    XmlElement idNode = (XmlElement) xnP.ChildNodes[0];
          Element idNode = (Element) xnP.elements().stream().findFirst().get();
          mColumn.setRefItemId(getRefItemId(idNode));
          break;
      }
    }
    return mColumn;
  }

  ///#endregion

  private void updateTableColumnsInfo(CdmColumnInfo columnInfo) {
    if (columnInfo == null) {
      return;
    }
    String refItemId = columnInfo.getRefItemId();
    if (!isNullOrEmpty(refItemId)) {

      var items = dataItems.stream().filter((item) -> {
        return refItemId.equals(item.getColumnId());
      }).toArray();

      if (items.length == 0) {
        throw new RuntimeException("不存在id={refItemId}的dataItem。");
      }

      CdmColumnInfo dataItem = (CdmColumnInfo) items[0];
      String length = dataItem.getLength();
      columnInfo.setLength(isNullOrEmpty(length) ? "0" : length);
      String precision = dataItem.getPrecision();
      columnInfo.setPrecision(isNullOrEmpty(precision) ? "0" : precision);
      columnInfo.setDataType(dataItem.getDataType());
      columnInfo.setCode(dataItem.getCode());
      columnInfo.setName(dataItem.getName());
    }
  }

  ///#region keys
  private void initKeys(Element xnKeys, CdmTableInfo pTable) {
    for (Element xnKey : xnKeys.elements()) {
      pTable.addKey(getKey(xnKey));
    }
  }

  ///#endregion

  ///#region util

  private CdmKey getKey(Element xnKey) {
    CdmKey mKey = new CdmKey();
//        XmlElement xe = (XmlElement) xnKey;
    String keyId = xnKey.attribute("Id").getValue();
//        mKey.setKeyId(xe.GetAttribute("Id"));
    mKey.setKeyId(keyId);
//        XmlNodeList xnKProperty = xe.ChildNodes;
    for (Element xnP : xnKey.elements()) {
      switch (xnP.getQName().getQualifiedName()) {
        case CdmNames.aObjectID:
          mKey.setObjectID(xnP.getStringValue());
          break;
        case CdmNames.aName:
          mKey.setName(xnP.getStringValue());
          break;
        case CdmNames.aCode:
          mKey.setCode(xnP.getStringValue());
          break;
        case CdmNames.aCreationDate:
          mKey.setCreationDate(Integer.parseInt(xnP.getText()));
          break;
        case CdmNames.aCreator:
          mKey.setCreator(xnP.getStringValue());
          break;
        case CdmNames.aModificationDate:
          mKey.setModificationDate(Integer.parseInt(xnP.getText()));
          break;
        case CdmNames.aModifier:
          mKey.setModifier(xnP.getStringValue());
          break;
        case CdmNames.cIdentifierAttributes:
          //XmlElement idNode = (XmlElement)Util.GetChildNode(xnP, "o:EntityAttribute");
//                    XmlElement idNode = (XmlElement) xnP.ChildNodes[0];
          Element idNode = xnP.elements().stream().findFirst().get();
          mKey.setRefItemId(getRefItemId(idNode));
          break;
      }
    }
    return mKey;
  }

  private String getTypeString(String s) {

    return s.replaceAll("[^(A-Za-z)]", "");

//        if (regex == null) {
//            String typeStringPattern = "[a-z]*[A-Z]*";
//            regex = new Regex(typeStringPattern);
//
//        }
////        Pattern patternAlphaNumericCheck = Pattern.compile("^[a-zA-Z0-9]$");
////        Matcher matcherAlphaNumericCheck = patternAlphaNumericCheck.matcher(login.getPassword());
//        String result = regex.Match(s).toString();
//        if (isNullOrEmpty(result)) {
//            throw new BeManagerException(exceptionCode, "类型不正确。");
//        }
//        return result;
  }

  private GspElementDataType getDataType(String s) {
    String type = getTypeString(s);

    if (CdmNames.CdmDataType_Image.equals(type) || CdmNames.CdmDataType_LongBinary.equals(type)
        || CdmNames.CdmDataType_Ole.equals(type) || CdmNames.CdmDataType_Multibyte.equals(type)
        || CdmNames.CdmDataType_VarMultibyte.equals(type) || CdmNames.CdmDataType_Binary
        .equals(type) || CdmNames.CdmDataType_Bitmap.equals(type)
        || CdmNames.CdmDataType_VariableBinary.equals(type)) {
      return GspElementDataType.Binary;

    } else if (CdmNames.CdmDataType_Boolean.equals(type)) {
      return GspElementDataType.Boolean;

    } else if (CdmNames.CdmDataType_Date.equals(type)) {
      return GspElementDataType.Date;

    } else if (CdmNames.CdmDataType_DateTime.equals(type) || CdmNames.CdmDataType_Time.equals(type)
        || CdmNames.CdmDataType_TimeStamp.equals(type)) {
      return GspElementDataType.DateTime;

    } else if (CdmNames.CdmDataType_Float.equals(type) || CdmNames.CdmDataType_LongFloat
        .equals(type) || CdmNames.CdmDataType_ShortFloat.equals(type)
        || CdmNames.CdmDataType_Decimal.equals(type) || CdmNames.CdmDataType_Money.equals(type)
        || CdmNames.CdmDataType_Number.equals(type)) {
      return GspElementDataType.Decimal;

    } else if (CdmNames.CdmDataType_Integer.equals(type) || CdmNames.CdmDataType_LongInteger
        .equals(type) || CdmNames.CdmDataType_ShortInteger.equals(type)
        || CdmNames.CdmDataType_Serial.equals(type) || CdmNames.CdmDataType_Byte.equals(type)) {
      return GspElementDataType.Integer;

    } else if (CdmNames.CdmDataType_Char.equals(type) || CdmNames.CdmDataType_VarCha.equals(type)
        || CdmNames.CdmDataType_LongCha.equals(type) || CdmNames.CdmDataType_LongVarCha
        .equals(type)) {
      return GspElementDataType.String;

    } else if (CdmNames.CdmDataType_Text.equals(type)) {
      return GspElementDataType.Text;
    } else {
//            throw new BeManagerException(exceptionCode, "不存在于cdm数据类型"+type+"对应的be字段类型。");
      throw new RuntimeException("不存在于cdm数据类型" + type + "对应的be字段类型。");
    }
  }

  private String getRefItemId(Element xe) {
//        return xe.GetAttribute("Ref");
    return xe.attribute("Ref").getValue();
  }

  ///#endregion

  public final CdmTableInfo FindTableByTableName(String tableName) {
    return FindTableByCode(tableName);
  }

  public final CdmTableInfo FindTableByCode(String tableCode) {
    for (CdmTableInfo mTable : tables) {
      if (mTable.getCode().equals(tableCode)) {
        return mTable;
      }
    }
    return null;
  }

  private boolean isNullOrEmpty(String str) {
    return str == null || "".equals(str);
  }
}
